package org.ft.zy.util;

import org.ft.zy.annotation.Column;
import org.ft.zy.annotation.Table;
import org.ft.zy.annotation.Transient;
import org.ft.zy.config.DatabaseConfig;
import org.ft.zy.enums.JavaType;
import org.ft.zy.po.ColumnDefine;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description mysql数据库查询
 * @Author zuoyue
 * @Date 2020/7/15 9:34
 **/
public class MysqlUtil {

    public static <T> List<T> list(Class<T> clazz) {
        List<T> list = new ArrayList<>();

        Connection conn = null;
        Statement stmt = null;
        try {
            // 注册 JDBC 驱动
            Class.forName(DatabaseConfig.JDBC_DRIVER);
            // 打开链接
            System.out.println("连接数据库...");
            conn = DriverManager.getConnection(DatabaseConfig.DB_URL, DatabaseConfig.USER, DatabaseConfig.PASSWORD);

            // 执行查询
            System.out.println(" 实例化Statement对象...");
            stmt = conn.createStatement();
            String table = getTableName(clazz);
            List<ColumnDefine> columnDefines = getColumns(clazz);
            String sql = buildSql(table, columnDefines);
//            sql = "SELECT id, title, content FROM biz_article";
            ResultSet rs = stmt.executeQuery(sql);

            // 展开结果集数据库
            while (rs.next()) {
                // 通过字段检索
                T obj = init(rs, clazz, columnDefines);
                list.add(obj);

            }
            // 完成后关闭
            rs.close();
            stmt.close();
            conn.close();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (stmt != null) stmt.close();
                if (conn != null) conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
        return list;
    }

    public static <T> T init(ResultSet rs, Class<T> clazz, List<ColumnDefine> columnDefines) throws InstantiationException, IllegalAccessException, NoSuchFieldException, SQLException {
        T obj = clazz.newInstance();
        for (ColumnDefine columnDefine : columnDefines) {
            Field field = clazz.getDeclaredField(columnDefine.getFieldName());
            field.setAccessible(true);
            Object value = parseValue(rs, columnDefine);
            field.set(obj, value);
        }
        return obj;
    }

    public static Object parseValue(ResultSet rs, ColumnDefine columnDefine) throws SQLException {
        String name = columnDefine.getName();
        switch (columnDefine.getJavaType()) {
            case FLOAT:
                return rs.getFloat(name);
            case DOUBLE:
                return rs.getDouble(name);
            case INTEGER:
                return rs.getInt(name);
            case LONG:
                return rs.getLong(name);
            case STRING:
                return rs.getString(name);
        }
        return rs.getObject(name);
    }

    public static String getTableName(Class clazz) throws NoSuchFieldException, IllegalAccessException {
        Table anno = (Table) clazz.getAnnotation(Table.class);
        String table = null;
        if (anno != null) {
            table = anno.value();

        } else {
            table = clazz.getName().toLowerCase();
        }
        return table;
    }

    public static List<ColumnDefine> getColumns(Class clazz) throws NoSuchFieldException, IllegalAccessException {
        Field[] fields = clazz.getDeclaredFields();
        List<ColumnDefine> list = new ArrayList<>();
        for (Field field : fields) {
            Annotation tAnno = field.getAnnotation(Transient.class);
            if (tAnno != null) continue;
            Column cAnno = field.getAnnotation(Column.class);
            if (cAnno != null) {
                String columnName = cAnno.value();
                String fName = field.getName();
                JavaType type = analysisType(field);
                ColumnDefine cd = ColumnDefine.builder().name(columnName).fieldName(fName).javaType(type).build();
                list.add(cd);
            } else {
                String fName = field.getName();
                JavaType type = analysisType(field);
                ColumnDefine cd = ColumnDefine.builder().name(fName).fieldName(fName).javaType(type).build();
                list.add(cd);
            }
        }

        return list;
    }

    public static JavaType analysisType(Field field) {
        Class clazz = field.getType();
        if (clazz == Integer.class) {
            return JavaType.INTEGER;
        } else if (clazz == Long.class) {
            return JavaType.LONG;
        } else if (clazz == String.class) {
            return JavaType.STRING;
        }
        return JavaType.STRING;
    }

    public static String buildSql(String table, List<ColumnDefine> columns) throws NoSuchFieldException, IllegalAccessException {
        StringBuilder sb = new StringBuilder();
        sb.append("select").append(' ');
        for (ColumnDefine columnDefine : columns) {
            sb.append(columnDefine.getName()).append(',');
        }
        sb.deleteCharAt(sb.length()-1);
        sb.append(' ');
        sb.append("from").append(' ');
        sb.append(table).append(' ');
        sb.append("limit 100");
        return sb.toString();
    }
}
